package tr.edu.ege.seagent.hobnobontology.instance;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;

import tr.edu.ege.seagent.hobnobontology.schema.HobNobVocabulary;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;

public class HobNobSPARQLQueries {

	/**
	 * Logger to logging
	 */
	private Logger logger;

	/**
	 * Model to query.
	 */
	private Model sampleModel;

	public HobNobSPARQLQueries() {
		sampleModel = new HobNobSampleModelCreator()
				.createNewInstanceWithIstanbulandCafePiNotification();
		setLogger();
	}

	/**
	 * This function provide us to find cities where the notifications occurs.
	 * 
	 * @return {@link HobNobResultSetSolution#getResultList()}
	 */
	public List<HobNobResultSetSolution> findCitiesOfLocationsOfNotifications() {

		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();
		logger.info("FIND CITIES OF LOCATIONS OF ALL NOTIFICATIONS");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = ""
				+ "PREFIX base: <"
				+ HobNobVocabulary.BASE_URI
				+ "> "
				+ "SELECT ?notification ?location ?dbpedia "
				+ "WHERE { "
				+ "          ?notification base:property_Notification_notificationAtLocation ?location. "
				+ "          ?location base:property_Location_locationHasDbpediaInfo ?dbpedia. "
				+ "      }";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();

			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("Nothing to find return : NULL");
		// return null if not found...
		return resultSetList;

	}

	/**
	 * This function provide us to traverse result set and analyze this set.
	 * 
	 * @param results
	 *            query result set
	 * @return list of result set
	 */
	private List<HobNobResultSetSolution> traverseResultSet(ResultSet results) {

		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();
		while (results.hasNext()) {
			QuerySolution querySolution = results.nextSolution();
			logger.trace("Object of HobNobResultSet Class is being created.");
			// creating new object with "results" parameter
			HobNobResultSetSolution resultSet = new HobNobResultSetSolution(
					querySolution);
			// result set is being analyzed...
			resultSet.analyzeToResultSet();
			logger.trace("ResultSet is being added to the list.");
			resultSetList.add(resultSet);
		}
		return resultSetList;
	}

	/**
	 * This method provide us to find location object which subject is seagent
	 * notification resource.
	 * 
	 * @return {@link HobNobResultSetSolution#getResultList()}
	 */
	public List<HobNobResultSetSolution> findLocationOfSeagentNotification() {

		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();
		logger.info("FIND LOCATION OF SEAGENT NOTIFICATION");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = ""
				+ "PREFIX base: <"
				+ HobNobVocabulary.BASE_URI
				+ "> "
				+ "SELECT ?location "
				+ "WHERE {"
				+ "			<"
				+ HobNobInstanceVocabulary.NOTIFICATION_SEAGENT_URI
				+ "> "
				+ "			base:property_Notification_notificationAtLocation ?location"
				+ "		}";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();

			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("Return: resultSetList");
		// return null if not found...
		return resultSetList;
	}

	/**
	 * This function provide us to find locations of all notification
	 * statements.
	 * 
	 * @return {@link HobNobResultSetSolution#getResultList()}
	 */
	public List<HobNobResultSetSolution> findLocationsOfAllNotifications() {

		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();
		logger.info("FIND LOCATIONS OF ALL NOTIFICATIONS");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = ""
				+ "PREFIX base: <"
				+ HobNobVocabulary.BASE_URI
				+ "> "
				+ "SELECT ?notification ?location "
				+ "WHERE { "
				+ "			?notification base:property_Notification_notificationAtLocation"
				+ "			?location " + "		}";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();
			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("Return: resultSetList.");

		return resultSetList;

	}

	/**
	 * Getter for sampleModel.
	 * 
	 * @return
	 */
	public Model getSampleModel() {
		return sampleModel;
	}

	/**
	 * Creates a logger for this instance with info level.
	 */
	private void setLogger() {
		this.logger = Logger.getLogger(HobNobSPARQLQueries.class);
		DOMConfigurator.configure("log4j.xml");
	}

	/**
	 * This function provide us to population that belong to cities where the
	 * notifications occur.
	 * 
	 * @return {@link HobNobResultSetSolution#getResultList()}
	 */
	public List<HobNobResultSetSolution> findPopulationOfLocations() {

		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();

		logger.info("FIND POPULATIONS' LOCATIONS OF ALL NOTIFICATIONS");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = ""
				+ "PREFIX base: <"
				+ HobNobVocabulary.BASE_URI
				+ "> "
				+ "PREFIX onto: <http://dbpedia.org/ontology/> "
				+ "SELECT ?notification ?location ?dbpedia ?population "
				+ "WHERE { "
				+ "          ?notification base:property_Notification_notificationAtLocation ?location. "
				+ "          ?location base:property_Location_locationHasDbpediaInfo ?dbpedia. "
				+ "			 SERVICE <http://dbpedia.org/sparql/> " + "				{"
				+ "					{?dbpedia onto:populationTotal ?population} "
				+ "					UNION "
				+ "						{?dbpedia onto:populationMetro ?population} "
				+ "				} " + "      }";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();
			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("return : RDFNode list");
		// return null if not found...
		return resultSetList;

	}

	public List<HobNobResultSetSolution> findPopulationWhichIsGreaterThanThreeMillion() {

		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();

		logger.info("FIND POPULATION WHICH IS GREATER THAN THREE MILLION");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = ""
				+ "PREFIX base: <"
				+ HobNobVocabulary.BASE_URI
				+ "> "
				+ "PREFIX onto: <http://dbpedia.org/ontology/> "
				+ "SELECT ?notification ?location ?dbpedia ?population "
				+ "WHERE { "
				+ "          ?notification base:property_Notification_notificationAtLocation ?location. "
				+ "          ?location base:property_Location_locationHasDbpediaInfo ?dbpedia. "
				+ "			 SERVICE <http://dbpedia.org/sparql/> " + "				{"
				+ "					{?dbpedia onto:populationTotal ?population} "
				+ "					UNION "
				+ "						{?dbpedia onto:populationMetro ?population} " + "				"
				+ "				FILTER(?population>3000000)" + "			 " + "     } "
				+ "      }";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();
			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("return : RDFNode list");
		// return null if not found...
		return resultSetList;
	}

	public List<HobNobResultSetSolution> findNotificationsThatOccurSameCity() {
		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();

		logger.info("FIND NOTIFICATIONS THAT OCCUR SAME CITY");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = ""
				+ "PREFIX base: <"
				+ HobNobVocabulary.BASE_URI
				+ "> "
				+ "PREFIX onto: <http://dbpedia.org/ontology/> "
				+ "SELECT  ?notification ?notificationX  ?member  ?dbpedia "
				+ "WHERE { "
				+ "          {?notificationX base:property_Notification_notificationAtLocation ?locationX "
				+ "				; base:property_Notification_notificationHasMember ?member. "
				+ "          ?locationX base:property_Location_locationHasDbpediaInfo ?dbpedia. }"
				+ "          {?notification base:property_Notification_notificationAtLocation ?locationY. "
				+ "          ?locationY base:property_Location_locationHasDbpediaInfo ?dbpedia. }"
				+ "			 FILTER(?notificationX != ?notification) " + "		 } "
				+ "			 LIMIT 2";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();
			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("return : RDFNode list");
		// return null if not found...
		return resultSetList;
	}

	public List<HobNobResultSetSolution> findNotificationsThatOccurSameCityOrderByCityName() {
		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();

		logger.info("FIND NOTIFICATIONS THAT OCCUR SAME CITY ORDER BY CITY NAME");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = ""
				+ "PREFIX base: <"
				+ HobNobVocabulary.BASE_URI
				+ "> "
				+ "PREFIX onto: <http://dbpedia.org/ontology/> "
				+ "SELECT  ?notification ?notificationX  ?member  ?dbpedia "
				+ "WHERE { "
				+ "          {?notificationX base:property_Notification_notificationAtLocation ?locationX "
				+ "				; base:property_Notification_notificationHasMember ?member. "
				+ "          ?locationX base:property_Location_locationHasDbpediaInfo ?dbpedia. }"
				+ "          {?notification base:property_Notification_notificationAtLocation ?locationY. "
				+ "          ?locationY base:property_Location_locationHasDbpediaInfo ?dbpedia. }"
				+ "			 FILTER(?notificationX != ?notification) " + "		 } "
				+ "			 ORDER BY ?dbpedia " + "			 LIMIT 2";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();
			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("return : RDFNode list");
		// return null if not found...
		return resultSetList;
	}

	public List<HobNobResultSetSolution> findPopulationOfLocationsOnTDBStore() {
		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();

		logger.info("FIND POPULATIONS' LOCATIONS OF ALL NOTIFICATIONS ON TDB STORE");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = ""
				+ "PREFIX base: <"
				+ HobNobVocabulary.BASE_URI
				+ "> "
				+ "PREFIX onto: <http://dbpedia.org/ontology/> "
				+ "SELECT ?notification ?location ?dbpedia ?population "
				+ "WHERE { "
				+ "			SERVICE <http://localhost:2020/sparql> { "
				+ "          ?notification base:property_Notification_notificationAtLocation ?location. "
				+ "          ?location base:property_Location_locationHasDbpediaInfo ?dbpedia. }"
				+ "			 SERVICE <http://dbpedia.org/sparql/> { "
				+ "					{?dbpedia onto:populationTotal ?population} "
				+ "					UNION "
				+ "						{?dbpedia onto:populationMetro ?population} "
				+ "				} " + "		 } ";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();
			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("return : RDFNode list");
		// return null if not found...
		return resultSetList;

	}

	public List<HobNobResultSetSolution> findAllNotificationsOverHttp() {
		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();

		logger.info("FIND ALL NOTIFICATIONS OVER HTTP");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = "" 
				+ "PREFIX base: <" + HobNobVocabulary.BASE_URI + "> " 
				+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
				+ "SELECT ?notification ?name ?surname " 
				+ "WHERE { "
				+ "			SERVICE <http://localhost:2020/sparql> { "
				+ "          ?notification rdf:type  base:class_Notification." 
				+ "			 ?notification base:property_Notification_notificationHasMember ?member." 
				+ "			 ?member base:property_Member_name ?name;" 
				+"				base:property_Member_surname ?surname."				
				+ "			} " 
				+ "		}";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();
			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("return : RDFNode list");
		// return null if not found...
		return resultSetList;

	}

	public List<HobNobResultSetSolution> findLocationOfNotificationOverHttp(String resourceURI) {
		List<HobNobResultSetSolution> resultSetList = new ArrayList<HobNobResultSetSolution>();
		double rangeValue = 0.05;
		logger.info("FIND LOCATION OF NOTIFICATIONS OVER HTTP");

		logger.debug("Query string is being created.");
		// create new queryString...
		String queryString = "" 
				+ "PREFIX base: <" + HobNobVocabulary.BASE_URI + "> " 
				+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
				+ "PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> "
				+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
				+ "SELECT ?location ?xCoordinate ?yCoordinate ?type ?label " 
				+ "WHERE { "
				+ "			SERVICE <http://localhost:2020/sparql> { "
				+ "          <" + resourceURI + "> base:property_Notification_notificationAtLocation  ?locationTDB.    "
				+ "			 ?locationTDB base:property_Location_xCoordinate ?xCoordinateTDB    					  " 
				+ "          ; base:property_Location_yCoordinate ?yCoordinateTDB." 
				+ "     	}SERVICE <http://linkedgeodata.org/sparql/> { " 
				+ "				?location geo:long ?yCoordinate " 
				+ " 			; geo:lat ?xCoordinate." 
				+ "				?location rdf:type ?type."
				+ "				?location rdfs:label ?label."			
				+ "				FILTER(((?xCoordinate > (?xCoordinateTDB- "+Double.toString(rangeValue)+")) && (?xCoordinate < (?xCoordinateTDB +" + Double.toString(rangeValue) +"))) && ((?yCoordinate > (?yCoordinateTDB - "+ Double.toString(rangeValue) +") ) && (?yCoordinate < (?yCoordinateTDB +" + Double.toString(rangeValue)+ "))))" 
				+ "				}	  					  "
				+ "			 																				  " 
				+ "		} LIMIT 10";

		logger.debug("New query is being created using the query string.");
		// create new query using the queryString ...
		Query query = QueryFactory.create(queryString);
		logger.debug("Query is being executed on the sampleModel.");
		// execute the query on the sampleModel...
		QueryExecution qe = QueryExecutionFactory.create(query, sampleModel);

		try {
			logger.debug("The results are being collected in the result set.");
			// collect the results in the result set...
			ResultSet results = qe.execSelect();			
			resultSetList = traverseResultSet(results);

		} catch (Exception e) {
			logger.error(e);
			System.out.println(e);
		}
		logger.debug("return : RDFNode list");
		// return null if not found...
		return resultSetList;

	}

}
